Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.61% covered (success)
96.61%
1196 / 1238
56.52% covered (warning)
56.52%
13 / 23
CRAP
0.00% covered (danger)
0.00%
0 / 1
PptCharts
96.61% covered (success)
96.61%
1196 / 1238
56.52% covered (warning)
56.52%
13 / 23
207
0.00% covered (danger)
0.00%
0 / 1
 render
90.91% covered (success)
90.91%
10 / 11
0.00% covered (danger)
0.00%
0 / 1
5.02
 writeChart
84.72% covered (warning)
84.72%
61 / 72
0.00% covered (danger)
0.00%
0 / 1
8.23
 writeSpreadsheet
93.75% covered (success)
93.75%
30 / 32
0.00% covered (danger)
0.00%
0 / 1
6.01
 writeElementWithValAttribute
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 writeSingleValueOrReference
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
2
 writeMultipleValuesOrReference
100.00% covered (success)
100.00%
29 / 29
100.00% covered (success)
100.00%
1 / 1
7
 writeTitle
100.00% covered (success)
100.00%
47 / 47
100.00% covered (success)
100.00%
1 / 1
3
 writePlotArea
100.00% covered (success)
100.00%
27 / 27
100.00% covered (success)
100.00%
1 / 1
12
 writeLegend
100.00% covered (success)
100.00%
46 / 46
100.00% covered (success)
100.00%
1 / 1
4
 writeLayout
76.92% covered (warning)
76.92%
20 / 26
0.00% covered (danger)
0.00%
0 / 1
5.31
 writeTypeArea
93.33% covered (success)
93.33%
42 / 45
0.00% covered (danger)
0.00%
0 / 1
9.02
 writeTypeBar
93.14% covered (success)
93.14%
95 / 102
0.00% covered (danger)
0.00%
0 / 1
16.08
 writeTypeBar3D
96.77% covered (success)
96.77%
90 / 93
0.00% covered (danger)
0.00%
0 / 1
14
 writeTypeDoughnut
95.35% covered (success)
95.35%
82 / 86
0.00% covered (danger)
0.00%
0 / 1
19
 writeTypePie
95.00% covered (success)
95.00%
76 / 80
0.00% covered (danger)
0.00%
0 / 1
14
 writeTypePie3D
100.00% covered (success)
100.00%
77 / 77
100.00% covered (success)
100.00%
1 / 1
12
 writeTypeLine
100.00% covered (success)
100.00%
82 / 82
100.00% covered (success)
100.00%
1 / 1
12
 writeTypeRadar
100.00% covered (success)
100.00%
80 / 80
100.00% covered (success)
100.00%
1 / 1
12
 writeTypeScatter
100.00% covered (success)
100.00%
86 / 86
100.00% covered (success)
100.00%
1 / 1
15
 writeChartRelationships
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 writeSeriesMarker
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
4
 writeAxis
99.41% covered (success)
99.41%
169 / 170
0.00% covered (danger)
0.00%
0 / 1
24
 writeAxisGridlines
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3/**
4 * This file is part of PHPPresentation - A pure PHP library for reading and writing
5 * presentations documents.
6 *
7 * PHPPresentation is free software distributed under the terms of the GNU Lesser
8 * General Public License version 3 as published by the Free Software Foundation.
9 *
10 * For the full copyright and license information, please read the LICENSE
11 * file that was distributed with this source code. For the full list of
12 * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors.
13 *
14 * @see        https://github.com/PHPOffice/PHPPresentation
15 *
16 * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
17 */
18
19declare(strict_types=1);
20
21namespace PhpOffice\PhpPresentation\Writer\PowerPoint2007;
22
23use PhpOffice\Common\Adapter\Zip\ZipInterface;
24use PhpOffice\Common\Drawing as CommonDrawing;
25use PhpOffice\Common\XMLWriter;
26use PhpOffice\PhpPresentation\Exception\FileRemoveException;
27use PhpOffice\PhpPresentation\Exception\UndefinedChartTypeException;
28use PhpOffice\PhpPresentation\PhpPresentation;
29use PhpOffice\PhpPresentation\Shape\Chart;
30use PhpOffice\PhpPresentation\Shape\Chart\Gridlines;
31use PhpOffice\PhpPresentation\Shape\Chart\Legend;
32use PhpOffice\PhpPresentation\Shape\Chart\PlotArea;
33use PhpOffice\PhpPresentation\Shape\Chart\Title;
34use PhpOffice\PhpPresentation\Shape\Chart\Type\Area;
35use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar;
36use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar3D;
37use PhpOffice\PhpPresentation\Shape\Chart\Type\Doughnut;
38use PhpOffice\PhpPresentation\Shape\Chart\Type\Line;
39use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie;
40use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie3D;
41use PhpOffice\PhpPresentation\Shape\Chart\Type\Radar;
42use PhpOffice\PhpPresentation\Shape\Chart\Type\Scatter;
43use PhpOffice\PhpPresentation\Style\Border;
44use PhpOffice\PhpPresentation\Style\Fill;
45use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
46use PhpOffice\PhpSpreadsheet\IOFactory;
47use PhpOffice\PhpSpreadsheet\Spreadsheet;
48
49class PptCharts extends AbstractDecoratorWriter
50{
51    public function render(): ZipInterface
52    {
53        for ($i = 0; $i < $this->getDrawingHashTable()->count(); ++$i) {
54            $shape = $this->getDrawingHashTable()->getByIndex($i);
55            if ($shape instanceof Chart) {
56                $this->getZip()->addFromString('ppt/charts/' . $shape->getIndexedFilename(), $this->writeChart($shape));
57
58                if ($shape->hasIncludedSpreadsheet()) {
59                    $this->getZip()->addFromString('ppt/charts/_rels/' . $shape->getIndexedFilename() . '.rels', $this->writeChartRelationships($shape));
60                    $pFilename = tempnam(sys_get_temp_dir(), 'PhpSpreadsheet');
61                    $this->getZip()->addFromString('ppt/embeddings/' . $shape->getIndexedFilename() . '.xlsx', $this->writeSpreadsheet($this->getPresentation(), $shape, $pFilename . '.xlsx'));
62
63                    // remove temp file
64                    if (false === @unlink($pFilename)) {
65                        throw new FileRemoveException($pFilename);
66                    }
67                }
68            }
69        }
70
71        return $this->getZip();
72    }
73
74    /**
75     * Write chart to XML format.
76     *
77     * @return string XML Output
78     */
79    protected function writeChart(Chart $chart): string
80    {
81        // Create XML writer
82        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
83
84        // XML header
85        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
86
87        // c:chartSpace
88        $objWriter->startElement('c:chartSpace');
89        $objWriter->writeAttribute('xmlns:c', 'http://schemas.openxmlformats.org/drawingml/2006/chart');
90        $objWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main');
91        $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
92
93        // c:date1904
94        $objWriter->startElement('c:date1904');
95        $objWriter->writeAttribute('val', '1');
96        $objWriter->endElement();
97
98        // c:lang
99        $objWriter->startElement('c:lang');
100        $objWriter->writeAttribute('val', 'en-US');
101        $objWriter->endElement();
102
103        // c:chart
104        $objWriter->startElement('c:chart');
105
106        // Title?
107        if ($chart->getTitle()->isVisible()) {
108            // Write title
109            $this->writeTitle($objWriter, $chart->getTitle());
110        }
111
112        // c:autoTitleDeleted
113        $objWriter->startElement('c:autoTitleDeleted');
114        $objWriter->writeAttribute('val', $chart->getTitle()->isVisible() ? '0' : '1');
115        $objWriter->endElement();
116
117        // c:view3D
118        $objWriter->startElement('c:view3D');
119
120        // c:rotX
121        $objWriter->startElement('c:rotX');
122        $objWriter->writeAttribute('val', $chart->getView3D()->getRotationX());
123        $objWriter->endElement();
124
125        // c:hPercent
126        $hPercent = $chart->getView3D()->getHeightPercent();
127        $objWriter->writeElementIf(null != $hPercent, 'c:hPercent', 'val', $hPercent);
128
129        // c:rotY
130        $objWriter->startElement('c:rotY');
131        $objWriter->writeAttribute('val', $chart->getView3D()->getRotationY());
132        $objWriter->endElement();
133
134        // c:depthPercent
135        $objWriter->startElement('c:depthPercent');
136        $objWriter->writeAttribute('val', $chart->getView3D()->getDepthPercent());
137        $objWriter->endElement();
138
139        // c:rAngAx
140        $objWriter->startElement('c:rAngAx');
141        $objWriter->writeAttribute('val', $chart->getView3D()->hasRightAngleAxes() ? '1' : '0');
142        $objWriter->endElement();
143
144        // c:perspective
145        $objWriter->startElement('c:perspective');
146        $objWriter->writeAttribute('val', $chart->getView3D()->getPerspective());
147        $objWriter->endElement();
148
149        $objWriter->endElement();
150
151        // Write plot area
152        $this->writePlotArea($objWriter, $chart->getPlotArea(), $chart);
153
154        // Legend?
155        if ($chart->getLegend()->isVisible()) {
156            // Write legend
157            $this->writeLegend($objWriter, $chart->getLegend());
158        }
159
160        // c:plotVisOnly
161        $objWriter->startElement('c:plotVisOnly');
162        $objWriter->writeAttribute('val', '1');
163        $objWriter->endElement();
164
165        // c:dispBlanksAs
166        $objWriter->startElement('c:dispBlanksAs');
167        $objWriter->writeAttribute('val', $chart->getDisplayBlankAs());
168        $objWriter->endElement();
169
170        $objWriter->endElement();
171
172        // c:spPr
173        $objWriter->startElement('c:spPr');
174
175        // Fill
176        $this->writeFill($objWriter, $chart->getFill());
177
178        // Border
179        if (Border::LINE_NONE != $chart->getBorder()->getLineStyle()) {
180            $this->writeBorder($objWriter, $chart->getBorder(), '');
181        }
182
183        // Shadow
184        if ($chart->getShadow()->isVisible()) {
185            // a:effectLst
186            $objWriter->startElement('a:effectLst');
187
188            // a:outerShdw
189            $objWriter->startElement('a:outerShdw');
190            $objWriter->writeAttribute('blurRad', CommonDrawing::pixelsToEmu($chart->getShadow()->getBlurRadius()));
191            $objWriter->writeAttribute('dist', CommonDrawing::pixelsToEmu($chart->getShadow()->getDistance()));
192            $objWriter->writeAttribute('dir', CommonDrawing::degreesToAngle((int) $chart->getShadow()->getDirection()));
193            $objWriter->writeAttribute('algn', $chart->getShadow()->getAlignment());
194            $objWriter->writeAttribute('rotWithShape', '0');
195
196            $this->writeColor($objWriter, $chart->getShadow()->getColor(), $chart->getShadow()->getAlpha());
197
198            $objWriter->endElement();
199
200            $objWriter->endElement();
201        }
202
203        $objWriter->endElement();
204
205        // External data?
206        if ($chart->hasIncludedSpreadsheet()) {
207            // c:externalData
208            $objWriter->startElement('c:externalData');
209            $objWriter->writeAttribute('r:id', 'rId1');
210
211            // c:autoUpdate
212            $objWriter->startElement('c:autoUpdate');
213            $objWriter->writeAttribute('val', '0');
214            $objWriter->endElement();
215
216            $objWriter->endElement();
217        }
218
219        $objWriter->endElement();
220
221        // Return
222        return $objWriter->getData();
223    }
224
225    /**
226     * Write chart to XML format.
227     *
228     * @return string String output
229     */
230    protected function writeSpreadsheet(PhpPresentation $presentation, Chart $chart, string $tempName): string
231    {
232        // Create new spreadsheet
233        $spreadsheet = new Spreadsheet();
234
235        // Set properties
236        $title = $chart->getTitle()->getText();
237        if (0 == strlen($title)) {
238            $title = 'Chart';
239        }
240        $spreadsheet->getProperties()
241            ->setCreator(
242                $presentation->getDocumentProperties()->getCreator()
243            )
244            ->setLastModifiedBy(
245                $presentation->getDocumentProperties()->getLastModifiedBy()
246            )
247            ->setTitle($title);
248
249        // Add chart data
250        $sheet = $spreadsheet->setActiveSheetIndex(0);
251        $sheet->setTitle('Sheet1');
252
253        // Write series
254        $seriesIndex = 0;
255        foreach ($chart->getPlotArea()->getType()->getSeries() as $series) {
256            // Title
257            $sheet->setCellValue(Coordinate::stringFromColumnIndex(2 + $seriesIndex) . 1, $series->getTitle());
258
259            // X-axis
260            $axisXData = array_keys($series->getValues());
261            $numAxisXData = count($axisXData);
262            for ($i = 0; $i < $numAxisXData; ++$i) {
263                $sheet->setCellValue('A' . ($i + 2), $axisXData[$i]);
264            }
265
266            // Y-axis
267            $axisYData = array_values($series->getValues());
268            $numAxisYData = count($axisYData);
269            for ($i = 0; $i < $numAxisYData; ++$i) {
270                $sheet->setCellValue(Coordinate::stringFromColumnIndex(2 + $seriesIndex) . ($i + 2), $axisYData[$i]);
271            }
272
273            ++$seriesIndex;
274        }
275
276        // Save to string
277        $writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
278        $writer->save($tempName);
279
280        // Load file in memory
281        $returnValue = file_get_contents($tempName);
282        if (false === @unlink($tempName)) {
283            throw new FileRemoveException($tempName);
284        }
285
286        return $returnValue;
287    }
288
289    /**
290     * Write element with value attribute.
291     *
292     * @param XMLWriter $objWriter XML Writer
293     */
294    protected function writeElementWithValAttribute(XMLWriter $objWriter, string $elementName, string $value): void
295    {
296        $objWriter->startElement($elementName);
297        $objWriter->writeAttribute('val', $value);
298        $objWriter->endElement();
299    }
300
301    /**
302     * Write single value or reference.
303     *
304     * @param XMLWriter $objWriter XML Writer
305     */
306    protected function writeSingleValueOrReference(XMLWriter $objWriter, bool $isReference, string $value, string $reference): void
307    {
308        if (!$isReference) {
309            // Value
310            $objWriter->writeElement('c:v', $value);
311
312            return;
313        }
314
315        // Reference and cache
316        // c:strRef
317        $objWriter->startElement('c:strRef');
318        // c:strRef/c:f
319        $objWriter->writeElement('c:f', $reference);
320        // c:strRef/c:strCache
321        $objWriter->startElement('c:strCache');
322        // c:strRef/c:strCache/c:ptCount
323        $objWriter->startElement('c:ptCount');
324        $objWriter->writeAttribute('val', '1');
325        $objWriter->endElement();
326
327        // c:strRef/c:strCache/c:pt
328        $objWriter->startElement('c:pt');
329        $objWriter->writeAttribute('idx', '0');
330        // c:strRef/c:strCache/c:pt/c:v
331        $objWriter->writeElement('c:v', $value);
332        // c:strRef/c:strCache/c:pt
333        $objWriter->endElement();
334        // c:strRef/c:strCache
335        $objWriter->endElement();
336        // c:strRef
337        $objWriter->endElement();
338    }
339
340    /**
341     * Write series value or reference.
342     *
343     * @param XMLWriter $objWriter XML Writer
344     * @param array<int, mixed> $values
345     */
346    protected function writeMultipleValuesOrReference(XMLWriter $objWriter, bool $isReference, array $values, string $reference): void
347    {
348        // c:strLit / c:numLit
349        // c:strRef / c:numRef
350        $referenceType = ($isReference ? 'Ref' : 'Lit');
351
352        // Get data type from first non-null value
353        $dataType = array_reduce($values, function ($carry, $item) {
354            if (!isset($item)) {
355                return $carry;
356            }
357
358            return is_numeric($item) ? 'num' : 'str';
359        }, 'num');
360
361        $objWriter->startElement('c:' . $dataType . $referenceType);
362
363        $numValues = count($values);
364        if (!$isReference) {
365            // Value
366
367            // c:ptCount
368            $objWriter->startElement('c:ptCount');
369            $objWriter->writeAttribute('val', count($values));
370            $objWriter->endElement();
371
372            // Add points
373            for ($i = 0; $i < $numValues; ++$i) {
374                // c:pt
375                $objWriter->startElement('c:pt');
376                $objWriter->writeAttribute('idx', $i);
377                $objWriter->writeElement('c:v', (string) ($values[$i]));
378                $objWriter->endElement();
379            }
380        } else {
381            // Reference
382            $objWriter->writeElement('c:f', $reference);
383            $objWriter->startElement('c:' . $dataType . 'Cache');
384
385            // c:ptCount
386            $objWriter->startElement('c:ptCount');
387            $objWriter->writeAttribute('val', count($values));
388            $objWriter->endElement();
389
390            // Add points
391            for ($i = 0; $i < $numValues; ++$i) {
392                // c:pt
393                $objWriter->startElement('c:pt');
394                $objWriter->writeAttribute('idx', $i);
395                $objWriter->writeElement('c:v', (string) ($values[$i]));
396                $objWriter->endElement();
397            }
398
399            $objWriter->endElement();
400        }
401
402        $objWriter->endElement();
403    }
404
405    /**
406     * Write Title.
407     */
408    protected function writeTitle(XMLWriter $objWriter, Title $subject): void
409    {
410        // c:title
411        $objWriter->startElement('c:title');
412
413        // c:tx
414        $objWriter->startElement('c:tx');
415
416        // c:rich
417        $objWriter->startElement('c:rich');
418
419        // a:bodyPr
420        $objWriter->writeElement('a:bodyPr', null);
421
422        // a:lstStyle
423        $objWriter->writeElement('a:lstStyle', null);
424
425        // a:p
426        $objWriter->startElement('a:p');
427
428        // a:pPr
429        $objWriter->startElement('a:pPr');
430        $objWriter->writeAttribute('algn', $subject->getAlignment()->getHorizontal());
431        $objWriter->writeAttribute('fontAlgn', $subject->getAlignment()->getVertical());
432        $objWriter->writeAttribute('marL', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginLeft()));
433        $objWriter->writeAttribute('marR', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginRight()));
434        $objWriter->writeAttribute('indent', CommonDrawing::pixelsToEmu($subject->getAlignment()->getIndent()));
435        $objWriter->writeAttribute('lvl', $subject->getAlignment()->getLevel());
436
437        // a:defRPr
438        $objWriter->writeElement('a:defRPr', null);
439
440        $objWriter->endElement();
441
442        // a:r
443        $objWriter->startElement('a:r');
444
445        // a:rPr
446        $objWriter->startElement('a:rPr');
447        $objWriter->writeAttribute('lang', 'en-US');
448        $objWriter->writeAttribute('dirty', '0');
449        $objWriter->writeAttribute('b', ($subject->getFont()->isBold() ? 'true' : 'false'));
450        $objWriter->writeAttribute('i', ($subject->getFont()->isItalic() ? 'true' : 'false'));
451        $objWriter->writeAttribute('strike', $subject->getFont()->getStrikethrough());
452        $objWriter->writeAttribute('sz', ($subject->getFont()->getSize() * 100));
453        $objWriter->writeAttribute('u', $subject->getFont()->getUnderline());
454        $objWriter->writeAttributeIf($subject->getFont()->getBaseline() !== 0, 'baseline', $subject->getFont()->getBaseline());
455        $objWriter->writeAttribute('cap', $subject->getFont()->getCapitalization());
456
457        // Font - a:solidFill
458        $objWriter->startElement('a:solidFill');
459
460        $this->writeColor($objWriter, $subject->getFont()->getColor());
461
462        $objWriter->endElement();
463
464        // Font - a:latin
465        $objWriter->startElement('a:latin');
466        $objWriter->writeAttribute('typeface', $subject->getFont()->getName());
467        $objWriter->endElement();
468
469        $objWriter->endElement();
470
471        // a:t
472        $objWriter->writeElement('a:t', $subject->getText());
473
474        $objWriter->endElement();
475
476        // a:endParaRPr
477        $objWriter->startElement('a:endParaRPr');
478        $objWriter->writeAttribute('lang', 'en-US');
479        $objWriter->writeAttribute('dirty', '0');
480        $objWriter->endElement();
481
482        $objWriter->endElement();
483
484        $objWriter->endElement();
485
486        $objWriter->endElement();
487
488        // Write layout
489        $this->writeLayout($objWriter, $subject);
490
491        // c:overlay
492        $objWriter->startElement('c:overlay');
493        $objWriter->writeAttribute('val', '0');
494        $objWriter->endElement();
495
496        $objWriter->endElement();
497    }
498
499    /**
500     * Write Plot Area.
501     *
502     * @param XMLWriter $objWriter XML Writer
503     */
504    protected function writePlotArea(XMLWriter $objWriter, PlotArea $subject, Chart $chart): void
505    {
506        // c:plotArea
507        $objWriter->startElement('c:plotArea');
508
509        // Write layout
510        $this->writeLayout($objWriter, $subject);
511
512        // Write chart
513        $chartType = $subject->getType();
514        if ($chartType instanceof Area) {
515            $this->writeTypeArea($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
516        } elseif ($chartType instanceof Bar) {
517            $this->writeTypeBar($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
518        } elseif ($chartType instanceof Bar3D) {
519            $this->writeTypeBar3D($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
520        } elseif ($chartType instanceof Doughnut) {
521            $this->writeTypeDoughnut($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
522        } elseif ($chartType instanceof Pie) {
523            $this->writeTypePie($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
524        } elseif ($chartType instanceof Pie3D) {
525            $this->writeTypePie3D($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
526        } elseif ($chartType instanceof Line) {
527            $this->writeTypeLine($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
528        } elseif ($chartType instanceof Radar) {
529            $this->writeTypeRadar($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
530        } elseif ($chartType instanceof Scatter) {
531            $this->writeTypeScatter($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
532        } else {
533            throw new UndefinedChartTypeException();
534        }
535
536        // Write X axis?
537        if ($chartType->hasAxisX()) {
538            $this->writeAxis($objWriter, $subject->getAxisX(), Chart\Axis::AXIS_X, $chartType);
539        }
540
541        // Write Y axis?
542        if ($chartType->hasAxisY()) {
543            $this->writeAxis($objWriter, $subject->getAxisY(), Chart\Axis::AXIS_Y, $chartType);
544        }
545
546        $objWriter->endElement();
547    }
548
549    /**
550     * Write Legend.
551     *
552     * @param XMLWriter $objWriter XML Writer
553     */
554    protected function writeLegend(XMLWriter $objWriter, Legend $subject): void
555    {
556        // c:legend
557        $objWriter->startElement('c:legend');
558
559        // c:legendPos
560        $objWriter->startElement('c:legendPos');
561        $objWriter->writeAttribute('val', $subject->getPosition());
562        $objWriter->endElement();
563
564        // Write layout
565        $this->writeLayout($objWriter, $subject);
566
567        // c:overlay
568        $objWriter->startElement('c:overlay');
569        $objWriter->writeAttribute('val', '0');
570        $objWriter->endElement();
571
572        // c:spPr
573        $objWriter->startElement('c:spPr');
574
575        // Fill
576        $this->writeFill($objWriter, $subject->getFill());
577
578        // Border
579        if (Border::LINE_NONE != $subject->getBorder()->getLineStyle()) {
580            $this->writeBorder($objWriter, $subject->getBorder(), '');
581        }
582
583        $objWriter->endElement();
584
585        // c:txPr
586        $objWriter->startElement('c:txPr');
587
588        // a:bodyPr
589        $objWriter->writeElement('a:bodyPr', null);
590
591        // a:lstStyle
592        $objWriter->writeElement('a:lstStyle', null);
593
594        // a:p
595        $objWriter->startElement('a:p');
596
597        // a:pPr
598        $objWriter->startElement('a:pPr');
599        $objWriter->writeAttribute('algn', $subject->getAlignment()->getHorizontal());
600        $objWriter->writeAttribute('fontAlgn', $subject->getAlignment()->getVertical());
601        $objWriter->writeAttribute('marL', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginLeft()));
602        $objWriter->writeAttribute('marR', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginRight()));
603        $objWriter->writeAttribute('indent', CommonDrawing::pixelsToEmu($subject->getAlignment()->getIndent()));
604        $objWriter->writeAttribute('lvl', $subject->getAlignment()->getLevel());
605
606        // a:defRPr
607        $objWriter->startElement('a:defRPr');
608
609        $objWriter->writeAttribute('b', ($subject->getFont()->isBold() ? 'true' : 'false'));
610        $objWriter->writeAttribute('i', ($subject->getFont()->isItalic() ? 'true' : 'false'));
611        $objWriter->writeAttribute('strike', $subject->getFont()->getStrikethrough());
612        $objWriter->writeAttribute('sz', ($subject->getFont()->getSize() * 100));
613        $objWriter->writeAttribute('u', $subject->getFont()->getUnderline());
614        $objWriter->writeAttributeIf($subject->getFont()->getBaseline() !== 0, 'baseline', $subject->getFont()->getBaseline());
615
616        // Font - a:solidFill
617        $objWriter->startElement('a:solidFill');
618
619        $this->writeColor($objWriter, $subject->getFont()->getColor());
620
621        $objWriter->endElement();
622
623        // Font - a:latin
624        $objWriter->startElement('a:latin');
625        $objWriter->writeAttribute('typeface', $subject->getFont()->getName());
626        $objWriter->endElement();
627
628        $objWriter->endElement();
629
630        $objWriter->endElement();
631
632        // a:endParaRPr
633        $objWriter->startElement('a:endParaRPr');
634        $objWriter->writeAttribute('lang', 'en-US');
635        $objWriter->writeAttribute('dirty', '0');
636        $objWriter->endElement();
637
638        $objWriter->endElement();
639
640        $objWriter->endElement();
641
642        $objWriter->endElement();
643    }
644
645    /**
646     * Write Layout.
647     *
648     * @param XMLWriter $objWriter XML Writer
649     * @param Legend|PlotArea|Title $subject
650     */
651    protected function writeLayout(XMLWriter $objWriter, $subject): void
652    {
653        // c:layout
654        $objWriter->startElement('c:layout');
655
656        // c:manualLayout
657        $objWriter->startElement('c:manualLayout');
658        // c:xMode
659        $objWriter->startElement('c:xMode');
660        $objWriter->writeAttribute('val', 'edge');
661        $objWriter->endElement();
662
663        // c:yMode
664        $objWriter->startElement('c:yMode');
665        $objWriter->writeAttribute('val', 'edge');
666        $objWriter->endElement();
667
668        if (0 != $subject->getOffsetX()) {
669            // c:x
670            $objWriter->startElement('c:x');
671            $objWriter->writeAttribute('val', $subject->getOffsetX());
672            $objWriter->endElement();
673        }
674
675        if (0 != $subject->getOffsetY()) {
676            // c:y
677            $objWriter->startElement('c:y');
678            $objWriter->writeAttribute('val', $subject->getOffsetY());
679            $objWriter->endElement();
680        }
681
682        if (0 != $subject->getWidth()) {
683            // c:w
684            $objWriter->startElement('c:w');
685            $objWriter->writeAttribute('val', $subject->getWidth());
686            $objWriter->endElement();
687        }
688
689        if (0 != $subject->getHeight()) {
690            // c:h
691            $objWriter->startElement('c:h');
692            $objWriter->writeAttribute('val', $subject->getHeight());
693            $objWriter->endElement();
694        }
695
696        $objWriter->endElement();
697        $objWriter->endElement();
698    }
699
700    /**
701     * Write Type Area.
702     *
703     * @param XMLWriter $objWriter XML Writer
704     */
705    protected function writeTypeArea(XMLWriter $objWriter, Area $subject, bool $includeSheet = false): void
706    {
707        // c:lineChart
708        $objWriter->startElement('c:areaChart');
709
710        // c:grouping
711        $objWriter->startElement('c:grouping');
712        $objWriter->writeAttribute('val', 'standard');
713        $objWriter->endElement();
714
715        // Write series
716        $seriesIndex = 0;
717        foreach ($subject->getSeries() as $series) {
718            // c:ser
719            $objWriter->startElement('c:ser');
720
721            // c:ser > c:idx
722            $objWriter->startElement('c:idx');
723            $objWriter->writeAttribute('val', $seriesIndex);
724            $objWriter->endElement();
725
726            // c:ser > c:order
727            $objWriter->startElement('c:order');
728            $objWriter->writeAttribute('val', $seriesIndex);
729            $objWriter->endElement();
730
731            // c:ser > c:tx
732            $objWriter->startElement('c:tx');
733            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
734            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
735            $objWriter->endElement();
736
737            // c:ser > c:dLbls
738            // @link : https://msdn.microsoft.com/en-us/library/documentformat.openxml.drawing.charts.areachartseries.aspx
739            $objWriter->startElement('c:dLbls');
740
741            // c:ser > c:dLbls > c:showVal
742            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
743
744            // c:ser > c:dLbls > c:showCatName
745            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
746
747            // c:ser > c:dLbls > c:showSerName
748            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
749
750            // c:ser > c:dLbls > c:showPercent
751            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
752
753            // c:ser > ##c:dLbls
754            $objWriter->endElement();
755
756            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
757                // c:spPr
758                $objWriter->startElement('c:spPr');
759                // Write fill
760                $this->writeFill($objWriter, $series->getFill());
761                // ## c:spPr
762                $objWriter->endElement();
763            }
764
765            // Write X axis data
766            $axisXData = array_keys($series->getValues());
767
768            // c:cat
769            $objWriter->startElement('c:cat');
770            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
771            $objWriter->endElement();
772
773            // Write Y axis data
774            $axisYData = array_values($series->getValues());
775
776            // c:val
777            $objWriter->startElement('c:val');
778            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
779            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
780            $objWriter->endElement();
781
782            $objWriter->endElement();
783
784            ++$seriesIndex;
785        }
786
787        // c:axId
788        $objWriter->startElement('c:axId');
789        $objWriter->writeAttribute('val', '52743552');
790        $objWriter->endElement();
791
792        // c:axId
793        $objWriter->startElement('c:axId');
794        $objWriter->writeAttribute('val', '52749440');
795        $objWriter->endElement();
796
797        $objWriter->endElement();
798    }
799
800    /**
801     * Write Type Bar.
802     *
803     * @param XMLWriter $objWriter XML Writer
804     */
805    protected function writeTypeBar(XMLWriter $objWriter, Bar $subject, bool $includeSheet = false): void
806    {
807        // c:barChart
808        $objWriter->startElement('c:barChart');
809
810        // c:barDir
811        $objWriter->startElement('c:barDir');
812        $objWriter->writeAttribute('val', $subject->getBarDirection());
813        $objWriter->endElement();
814
815        // c:grouping
816        $objWriter->startElement('c:grouping');
817        $objWriter->writeAttribute('val', $subject->getBarGrouping());
818        $objWriter->endElement();
819
820        // Write series
821        $seriesIndex = 0;
822        foreach ($subject->getSeries() as $series) {
823            // c:ser
824            $objWriter->startElement('c:ser');
825
826            // c:idx
827            $objWriter->startElement('c:idx');
828            $objWriter->writeAttribute('val', $seriesIndex);
829            $objWriter->endElement();
830
831            // c:order
832            $objWriter->startElement('c:order');
833            $objWriter->writeAttribute('val', $seriesIndex);
834            $objWriter->endElement();
835
836            // c:tx
837            $objWriter->startElement('c:tx');
838            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
839            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
840            $objWriter->endElement();
841
842            // Fills for points?
843            $dataPointFills = $series->getDataPointFills();
844            foreach ($dataPointFills as $key => $value) {
845                // c:dPt
846                $objWriter->startElement('c:dPt');
847
848                // c:idx
849                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
850
851                if (Fill::FILL_NONE != $value->getFillType()) {
852                    // c:spPr
853                    $objWriter->startElement('c:spPr');
854                    // Write fill
855                    $this->writeFill($objWriter, $value);
856                    // ## c:spPr
857                    $objWriter->endElement();
858                }
859
860                // ## c:dPt
861                $objWriter->endElement();
862            }
863
864            // c:dLbls
865            $objWriter->startElement('c:dLbls');
866
867            if ($series->hasDlblNumFormat()) {
868                //c:numFmt
869                $objWriter->startElement('c:numFmt');
870                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
871                $objWriter->writeAttribute('sourceLinked', '0');
872                $objWriter->endElement();
873            }
874
875            // c:txPr
876            $objWriter->startElement('c:txPr');
877
878            // a:bodyPr
879            $objWriter->writeElement('a:bodyPr');
880
881            // a:lstStyle
882            $objWriter->writeElement('a:lstStyle');
883
884            // a:p
885            $objWriter->startElement('a:p');
886
887            // a:pPr
888            $objWriter->startElement('a:pPr');
889
890            // a:defRPr
891            $objWriter->startElement('a:defRPr');
892            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
893            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
894            $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough());
895            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
896            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
897            $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline());
898
899            // a:solidFill
900            $objWriter->startElement('a:solidFill');
901            $this->writeColor($objWriter, $series->getFont()->getColor());
902            $objWriter->endElement();
903
904            // a:latin
905            $objWriter->startElement('a:latin');
906            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
907            $objWriter->endElement();
908
909            // a:ea
910            $objWriter->startElement('a:ea');
911            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
912            $objWriter->endElement();
913
914            // >a:defRPr
915            $objWriter->endElement();
916            // >a:pPr
917            $objWriter->endElement();
918
919            // a:endParaRPr
920            $objWriter->startElement('a:endParaRPr');
921            $objWriter->writeAttribute('lang', 'en-US');
922            $objWriter->writeAttribute('dirty', '0');
923            $objWriter->endElement();
924
925            // >a:p
926            $objWriter->endElement();
927            // >a:lstStyle
928            $objWriter->endElement();
929
930            // c:dLblPos
931            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
932
933            // c:showVal
934            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
935
936            // c:showCatName
937            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
938
939            // c:showSerName
940            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
941
942            // c:showPercent
943            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
944
945            // c:separator
946            $objWriter->writeElement('c:separator', $series->hasShowSeparator() ? $series->getSeparator() : '');
947
948            // c:showLeaderLines
949            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
950
951            $objWriter->endElement();
952
953            // c:spPr
954            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
955                // c:spPr
956                $objWriter->startElement('c:spPr');
957                // Write fill
958                $this->writeFill($objWriter, $series->getFill());
959                // ## c:spPr
960                $objWriter->endElement();
961            }
962
963            // Write X axis data
964            $axisXData = array_keys($series->getValues());
965
966            // c:cat
967            $objWriter->startElement('c:cat');
968            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
969            $objWriter->endElement();
970
971            // Write Y axis data
972            $axisYData = array_values($series->getValues());
973
974            // c:val
975            $objWriter->startElement('c:val');
976            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
977            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
978            $objWriter->endElement();
979
980            $objWriter->endElement();
981
982            ++$seriesIndex;
983        }
984
985        // c:gapWidth
986        $objWriter->startElement('c:gapWidth');
987        $objWriter->writeAttribute('val', $subject->getGapWidthPercent());
988        $objWriter->endElement();
989
990        // c:overlap
991        $objWriter->startElement('c:overlap');
992        $objWriter->writeAttribute('val', $subject->getOverlapWidthPercent());
993        $objWriter->endElement();
994
995        // c:axId
996        $objWriter->startElement('c:axId');
997        $objWriter->writeAttribute('val', '52743552');
998        $objWriter->endElement();
999
1000        // c:axId
1001        $objWriter->startElement('c:axId');
1002        $objWriter->writeAttribute('val', '52749440');
1003        $objWriter->endElement();
1004
1005        // c:extLst
1006        $objWriter->startElement('c:extLst');
1007        $objWriter->endElement();
1008
1009        $objWriter->endElement();
1010    }
1011
1012    /**
1013     * Write Type Bar3D.
1014     *
1015     * @param XMLWriter $objWriter XML Writer
1016     */
1017    protected function writeTypeBar3D(XMLWriter $objWriter, Bar3D $subject, bool $includeSheet = false): void
1018    {
1019        // c:bar3DChart
1020        $objWriter->startElement('c:bar3DChart');
1021
1022        // c:barDir
1023        $objWriter->startElement('c:barDir');
1024        $objWriter->writeAttribute('val', $subject->getBarDirection());
1025        $objWriter->endElement();
1026
1027        // c:grouping
1028        $objWriter->startElement('c:grouping');
1029        $objWriter->writeAttribute('val', $subject->getBarGrouping());
1030        $objWriter->endElement();
1031
1032        // Write series
1033        $seriesIndex = 0;
1034        foreach ($subject->getSeries() as $series) {
1035            // c:ser
1036            $objWriter->startElement('c:ser');
1037
1038            // c:idx
1039            $objWriter->startElement('c:idx');
1040            $objWriter->writeAttribute('val', $seriesIndex);
1041            $objWriter->endElement();
1042
1043            // c:order
1044            $objWriter->startElement('c:order');
1045            $objWriter->writeAttribute('val', $seriesIndex);
1046            $objWriter->endElement();
1047
1048            // c:tx
1049            $objWriter->startElement('c:tx');
1050            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1051            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1052            $objWriter->endElement();
1053
1054            // Fills for points?
1055            $dataPointFills = $series->getDataPointFills();
1056            foreach ($dataPointFills as $key => $value) {
1057                // c:dPt
1058                $objWriter->startElement('c:dPt');
1059
1060                // c:idx
1061                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1062
1063                if (Fill::FILL_NONE != $value->getFillType()) {
1064                    // c:spPr
1065                    $objWriter->startElement('c:spPr');
1066                    // Write fill
1067                    $this->writeFill($objWriter, $value);
1068                    // ## c:spPr
1069                    $objWriter->endElement();
1070                }
1071
1072                // ## c:dPt
1073                $objWriter->endElement();
1074            }
1075
1076            // c:dLbls
1077            $objWriter->startElement('c:dLbls');
1078
1079            // c:txPr
1080            $objWriter->startElement('c:txPr');
1081
1082            // a:bodyPr
1083            $objWriter->writeElement('a:bodyPr', null);
1084
1085            // a:lstStyle
1086            $objWriter->writeElement('a:lstStyle', null);
1087
1088            // a:p
1089            $objWriter->startElement('a:p');
1090
1091            // a:pPr
1092            $objWriter->startElement('a:pPr');
1093
1094            // a:defRPr
1095            $objWriter->startElement('a:defRPr');
1096
1097            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1098            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1099            $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough());
1100            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1101            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1102            $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline());
1103
1104            // Font - a:solidFill
1105            $objWriter->startElement('a:solidFill');
1106
1107            $this->writeColor($objWriter, $series->getFont()->getColor());
1108
1109            $objWriter->endElement();
1110
1111            // Font - a:latin
1112            $objWriter->startElement('a:latin');
1113            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1114            $objWriter->endElement();
1115            // a:ea
1116            $objWriter->startElement('a:ea');
1117            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1118            $objWriter->endElement();
1119
1120            $objWriter->endElement();
1121
1122            $objWriter->endElement();
1123
1124            // a:endParaRPr
1125            $objWriter->startElement('a:endParaRPr');
1126            $objWriter->writeAttribute('lang', 'en-US');
1127            $objWriter->writeAttribute('dirty', '0');
1128            $objWriter->endElement();
1129
1130            $objWriter->endElement();
1131
1132            $objWriter->endElement();
1133
1134            // c:showVal
1135            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1136
1137            // c:showCatName
1138            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1139
1140            // c:showSerName
1141            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1142
1143            // c:showPercent
1144            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1145
1146            // c:showLeaderLines
1147            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1148
1149            $objWriter->endElement();
1150
1151            // c:spPr
1152            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
1153                // c:spPr
1154                $objWriter->startElement('c:spPr');
1155                // Write fill
1156                $this->writeFill($objWriter, $series->getFill());
1157                // ## c:spPr
1158                $objWriter->endElement();
1159            }
1160
1161            // Write X axis data
1162            $axisXData = array_keys($series->getValues());
1163
1164            // c:cat
1165            $objWriter->startElement('c:cat');
1166            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1167            $objWriter->endElement();
1168
1169            // Write Y axis data
1170            $axisYData = array_values($series->getValues());
1171
1172            // c:val
1173            $objWriter->startElement('c:val');
1174            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
1175            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1176            $objWriter->endElement();
1177
1178            $objWriter->endElement();
1179
1180            ++$seriesIndex;
1181        }
1182
1183        // c:gapWidth
1184        $objWriter->startElement('c:gapWidth');
1185        $objWriter->writeAttribute('val', $subject->getGapWidthPercent());
1186        $objWriter->endElement();
1187
1188        // c:axId
1189        $objWriter->startElement('c:axId');
1190        $objWriter->writeAttribute('val', '52743552');
1191        $objWriter->endElement();
1192
1193        // c:axId
1194        $objWriter->startElement('c:axId');
1195        $objWriter->writeAttribute('val', '52749440');
1196        $objWriter->endElement();
1197
1198        // c:axId
1199        $objWriter->startElement('c:axId');
1200        $objWriter->writeAttribute('val', '0');
1201        $objWriter->endElement();
1202
1203        $objWriter->endElement();
1204    }
1205
1206    /**
1207     * Write Type Pie.
1208     *
1209     * @param XMLWriter $objWriter XML Writer
1210     */
1211    protected function writeTypeDoughnut(XMLWriter $objWriter, Doughnut $subject, bool $includeSheet = false): void
1212    {
1213        // c:pieChart
1214        $objWriter->startElement('c:doughnutChart');
1215
1216        // c:varyColors
1217        $objWriter->startElement('c:varyColors');
1218        $objWriter->writeAttribute('val', '1');
1219        $objWriter->endElement();
1220
1221        // Write series
1222        $seriesIndex = 0;
1223        foreach ($subject->getSeries() as $series) {
1224            // c:ser
1225            $objWriter->startElement('c:ser');
1226
1227            // c:idx
1228            $objWriter->startElement('c:idx');
1229            $objWriter->writeAttribute('val', $seriesIndex);
1230            $objWriter->endElement();
1231
1232            // c:order
1233            $objWriter->startElement('c:order');
1234            $objWriter->writeAttribute('val', $seriesIndex);
1235            $objWriter->endElement();
1236
1237            // c:tx
1238            $objWriter->startElement('c:tx');
1239            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1240            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1241            $objWriter->endElement();
1242
1243            // Fills for points?
1244            $dataPointFills = $series->getDataPointFills();
1245            foreach ($dataPointFills as $key => $value) {
1246                // c:dPt
1247                $objWriter->startElement('c:dPt');
1248                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1249                // c:dPt/c:spPr
1250                $objWriter->startElement('c:spPr');
1251                $this->writeFill($objWriter, $value);
1252                // c:dPt/##c:spPr
1253                $objWriter->endElement();
1254                // ##c:dPt
1255                $objWriter->endElement();
1256            }
1257
1258            // Write X axis data
1259            $axisXData = array_keys($series->getValues());
1260
1261            // c:cat
1262            $objWriter->startElement('c:cat');
1263            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1264            $objWriter->endElement();
1265
1266            // Write Y axis data
1267            $axisYData = array_values($series->getValues());
1268
1269            // c:val
1270            $objWriter->startElement('c:val');
1271            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
1272            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1273            $objWriter->endElement();
1274
1275            $objWriter->endElement();
1276
1277            ++$seriesIndex;
1278        }
1279
1280        if (isset($series) && is_object($series) && $series instanceof Chart\Series) {
1281            // c:dLbls
1282            $objWriter->startElement('c:dLbls');
1283
1284            if ($series->hasDlblNumFormat()) {
1285                //c:numFmt
1286                $objWriter->startElement('c:numFmt');
1287                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
1288                $objWriter->writeAttribute('sourceLinked', '0');
1289                $objWriter->endElement();
1290            }
1291
1292            // c:dLbls\c:txPr
1293            $objWriter->startElement('c:txPr');
1294            $objWriter->writeElement('a:bodyPr', null);
1295            $objWriter->writeElement('a:lstStyle', null);
1296
1297            // c:dLbls\c:txPr\a:p
1298            $objWriter->startElement('a:p');
1299
1300            // c:dLbls\c:txPr\a:p\a:pPr
1301            $objWriter->startElement('a:pPr');
1302
1303            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr
1304            $objWriter->startElement('a:defRPr');
1305            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1306            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1307            $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough());
1308            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1309            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1310            $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline());
1311
1312            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\a:solidFill
1313            $objWriter->startElement('a:solidFill');
1314            $this->writeColor($objWriter, $series->getFont()->getColor());
1315            $objWriter->endElement();
1316
1317            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\a:latin
1318            $objWriter->startElement('a:latin');
1319            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1320            $objWriter->endElement();
1321            // a:ea
1322            $objWriter->startElement('a:ea');
1323            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1324            $objWriter->endElement();
1325
1326            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\
1327            $objWriter->endElement();
1328            // c:dLbls\c:txPr\a:p\a:pPr\
1329            $objWriter->endElement();
1330
1331            // c:dLbls\c:txPr\a:p\a:endParaRPr
1332            $objWriter->startElement('a:endParaRPr');
1333            $objWriter->writeAttribute('lang', 'en-US');
1334            $objWriter->writeAttribute('dirty', '0');
1335            $objWriter->endElement();
1336
1337            // c:dLbls\c:txPr\a:p\
1338            $objWriter->endElement();
1339            // c:dLbls\c:txPr\
1340            $objWriter->endElement();
1341
1342            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1343            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1344            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1345            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1346            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1347            $this->writeElementWithValAttribute($objWriter, 'c:showBubbleSize', '0');
1348            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1349
1350            $separator = $series->getSeparator();
1351            if (!empty($separator) && PHP_EOL != $separator) {
1352                // c:dLbls\c:separator
1353                $objWriter->writeElement('c:separator', $separator);
1354            }
1355
1356            // c:dLbls\
1357            $objWriter->endElement();
1358        }
1359
1360        $this->writeElementWithValAttribute($objWriter, 'c:firstSliceAng', '0');
1361        $this->writeElementWithValAttribute($objWriter, 'c:holeSize', (string) $subject->getHoleSize());
1362
1363        $objWriter->endElement();
1364    }
1365
1366    /**
1367     * Write Type Pie.
1368     *
1369     * @param XMLWriter $objWriter XML Writer
1370     */
1371    protected function writeTypePie(XMLWriter $objWriter, Pie $subject, bool $includeSheet = false): void
1372    {
1373        // c:pieChart
1374        $objWriter->startElement('c:pieChart');
1375
1376        // c:varyColors
1377        $objWriter->startElement('c:varyColors');
1378        $objWriter->writeAttribute('val', '1');
1379        $objWriter->endElement();
1380
1381        // Write series
1382        $seriesIndex = 0;
1383        foreach ($subject->getSeries() as $series) {
1384            // c:ser
1385            $objWriter->startElement('c:ser');
1386
1387            // c:idx
1388            $objWriter->startElement('c:idx');
1389            $objWriter->writeAttribute('val', $seriesIndex);
1390            $objWriter->endElement();
1391
1392            // c:order
1393            $objWriter->startElement('c:order');
1394            $objWriter->writeAttribute('val', $seriesIndex);
1395            $objWriter->endElement();
1396
1397            // c:tx
1398            $objWriter->startElement('c:tx');
1399            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1400            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1401            $objWriter->endElement();
1402
1403            // Fills for points?
1404            $dataPointFills = $series->getDataPointFills();
1405            foreach ($dataPointFills as $key => $value) {
1406                // c:dPt
1407                $objWriter->startElement('c:dPt');
1408                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1409                // c:dPt/c:spPr
1410                $objWriter->startElement('c:spPr');
1411                $this->writeFill($objWriter, $value);
1412                // c:dPt/##c:spPr
1413                $objWriter->endElement();
1414                // ##c:dPt
1415                $objWriter->endElement();
1416            }
1417
1418            // c:dLbls
1419            $objWriter->startElement('c:dLbls');
1420
1421            if ($series->hasDlblNumFormat()) {
1422                //c:numFmt
1423                $objWriter->startElement('c:numFmt');
1424                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
1425                $objWriter->writeAttribute('sourceLinked', '0');
1426                $objWriter->endElement();
1427            }
1428
1429            // c:txPr
1430            $objWriter->startElement('c:txPr');
1431
1432            // a:bodyPr
1433            $objWriter->writeElement('a:bodyPr', null);
1434
1435            // a:lstStyle
1436            $objWriter->writeElement('a:lstStyle', null);
1437
1438            // a:p
1439            $objWriter->startElement('a:p');
1440
1441            // a:pPr
1442            $objWriter->startElement('a:pPr');
1443
1444            // a:defRPr
1445            $objWriter->startElement('a:defRPr');
1446
1447            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1448            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1449            $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough());
1450            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1451            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1452            $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline());
1453
1454            // Font - a:solidFill
1455            $objWriter->startElement('a:solidFill');
1456
1457            $this->writeColor($objWriter, $series->getFont()->getColor());
1458
1459            $objWriter->endElement();
1460
1461            // Font - a:latin
1462            $objWriter->startElement('a:latin');
1463            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1464            $objWriter->endElement();
1465            // a:ea
1466            $objWriter->startElement('a:ea');
1467            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1468            $objWriter->endElement();
1469
1470            $objWriter->endElement();
1471
1472            $objWriter->endElement();
1473
1474            // a:endParaRPr
1475            $objWriter->startElement('a:endParaRPr');
1476            $objWriter->writeAttribute('lang', 'en-US');
1477            $objWriter->writeAttribute('dirty', '0');
1478            $objWriter->endElement();
1479
1480            $objWriter->endElement();
1481
1482            $objWriter->endElement();
1483
1484            // c:dLblPos
1485            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
1486
1487            // c:showLegendKey
1488            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1489
1490            // c:showVal
1491            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1492
1493            // c:showCatName
1494            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1495
1496            // c:showSerName
1497            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1498
1499            // c:showPercent
1500            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1501
1502            // c:showLeaderLines
1503            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1504
1505            $objWriter->endElement();
1506
1507            // Write X axis data
1508            $axisXData = array_keys($series->getValues());
1509
1510            // c:cat
1511            $objWriter->startElement('c:cat');
1512            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1513            $objWriter->endElement();
1514
1515            // Write Y axis data
1516            $axisYData = array_values($series->getValues());
1517
1518            // c:val
1519            $objWriter->startElement('c:val');
1520            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
1521            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1522            $objWriter->endElement();
1523
1524            $objWriter->endElement();
1525
1526            ++$seriesIndex;
1527        }
1528
1529        $objWriter->endElement();
1530    }
1531
1532    /**
1533     * Write Type Pie3D.
1534     *
1535     * @param XMLWriter $objWriter XML Writer
1536     */
1537    protected function writeTypePie3D(XMLWriter $objWriter, Pie3D $subject, bool $includeSheet = false): void
1538    {
1539        // c:pie3DChart
1540        $objWriter->startElement('c:pie3DChart');
1541
1542        // c:varyColors
1543        $objWriter->startElement('c:varyColors');
1544        $objWriter->writeAttribute('val', '1');
1545        $objWriter->endElement();
1546
1547        // Write series
1548        $seriesIndex = 0;
1549        foreach ($subject->getSeries() as $series) {
1550            // c:ser
1551            $objWriter->startElement('c:ser');
1552
1553            // c:idx
1554            $objWriter->startElement('c:idx');
1555            $objWriter->writeAttribute('val', $seriesIndex);
1556            $objWriter->endElement();
1557
1558            // c:order
1559            $objWriter->startElement('c:order');
1560            $objWriter->writeAttribute('val', $seriesIndex);
1561            $objWriter->endElement();
1562
1563            // c:tx
1564            $objWriter->startElement('c:tx');
1565            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1566            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1567            $objWriter->endElement();
1568
1569            // c:explosion
1570            $objWriter->startElement('c:explosion');
1571            $objWriter->writeAttribute('val', $subject->getExplosion());
1572            $objWriter->endElement();
1573
1574            // Fills for points?
1575            $dataPointFills = $series->getDataPointFills();
1576            foreach ($dataPointFills as $key => $value) {
1577                // c:dPt
1578                $objWriter->startElement('c:dPt');
1579                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1580                // c:dPt/c:spPr
1581                $objWriter->startElement('c:spPr');
1582                $this->writeFill($objWriter, $value);
1583                // c:dPt/##c:spPr
1584                $objWriter->endElement();
1585                // ##c:dPt
1586                $objWriter->endElement();
1587            }
1588
1589            // c:dLbls
1590            $objWriter->startElement('c:dLbls');
1591
1592            // c:txPr
1593            $objWriter->startElement('c:txPr');
1594
1595            // a:bodyPr
1596            $objWriter->writeElement('a:bodyPr', null);
1597
1598            // a:lstStyle
1599            $objWriter->writeElement('a:lstStyle', null);
1600
1601            // a:p
1602            $objWriter->startElement('a:p');
1603
1604            // a:pPr
1605            $objWriter->startElement('a:pPr');
1606
1607            // a:defRPr
1608            $objWriter->startElement('a:defRPr');
1609
1610            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1611            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1612            $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough());
1613            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1614            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1615            $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline());
1616
1617            // Font - a:solidFill
1618            $objWriter->startElement('a:solidFill');
1619
1620            $this->writeColor($objWriter, $series->getFont()->getColor());
1621
1622            $objWriter->endElement();
1623
1624            // Font - a:latin
1625            $objWriter->startElement('a:latin');
1626            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1627            $objWriter->endElement();
1628            // a:ea
1629            $objWriter->startElement('a:ea');
1630            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1631            $objWriter->endElement();
1632
1633            $objWriter->endElement();
1634
1635            $objWriter->endElement();
1636
1637            // a:endParaRPr
1638            $objWriter->startElement('a:endParaRPr');
1639            $objWriter->writeAttribute('lang', 'en-US');
1640            $objWriter->writeAttribute('dirty', '0');
1641            $objWriter->endElement();
1642
1643            $objWriter->endElement();
1644
1645            $objWriter->endElement();
1646
1647            // c:dLblPos
1648            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
1649
1650            // c:showVal
1651            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1652
1653            // c:showCatName
1654            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1655
1656            // c:showSerName
1657            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1658
1659            // c:showPercent
1660            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1661
1662            // c:showLeaderLines
1663            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1664
1665            $objWriter->endElement();
1666
1667            // Write X axis data
1668            $axisXData = array_keys($series->getValues());
1669
1670            // c:cat
1671            $objWriter->startElement('c:cat');
1672            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1673            $objWriter->endElement();
1674
1675            // Write Y axis data
1676            $axisYData = array_values($series->getValues());
1677
1678            // c:val
1679            $objWriter->startElement('c:val');
1680            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
1681            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1682            $objWriter->endElement();
1683
1684            $objWriter->endElement();
1685
1686            ++$seriesIndex;
1687        }
1688
1689        $objWriter->endElement();
1690    }
1691
1692    /**
1693     * Write Type Line.
1694     *
1695     * @param XMLWriter $objWriter XML Writer
1696     */
1697    protected function writeTypeLine(XMLWriter $objWriter, Line $subject, bool $includeSheet = false): void
1698    {
1699        // c:lineChart
1700        $objWriter->startElement('c:lineChart');
1701
1702        // c:grouping
1703        $objWriter->startElement('c:grouping');
1704        $objWriter->writeAttribute('val', 'standard');
1705        $objWriter->endElement();
1706
1707        // Write series
1708        $seriesIndex = 0;
1709        foreach ($subject->getSeries() as $series) {
1710            // c:ser
1711            $objWriter->startElement('c:ser');
1712
1713            // c:idx
1714            $objWriter->startElement('c:idx');
1715            $objWriter->writeAttribute('val', $seriesIndex);
1716            $objWriter->endElement();
1717
1718            // c:order
1719            $objWriter->startElement('c:order');
1720            $objWriter->writeAttribute('val', $seriesIndex);
1721            $objWriter->endElement();
1722
1723            // c:tx
1724            $objWriter->startElement('c:tx');
1725            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1726            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1727            $objWriter->endElement();
1728
1729            // c:spPr
1730            $objWriter->startElement('c:spPr');
1731            // Write fill
1732            $this->writeFill($objWriter, $series->getFill());
1733            // Write outline
1734            $this->writeOutline($objWriter, $series->getOutline());
1735            // ## c:spPr
1736            $objWriter->endElement();
1737
1738            // Marker
1739            $this->writeSeriesMarker($objWriter, $series->getMarker());
1740
1741            // c:dLbls
1742            $objWriter->startElement('c:dLbls');
1743
1744            // c:txPr
1745            $objWriter->startElement('c:txPr');
1746
1747            // a:bodyPr
1748            $objWriter->writeElement('a:bodyPr', null);
1749
1750            // a:lstStyle
1751            $objWriter->writeElement('a:lstStyle', null);
1752
1753            // a:p
1754            $objWriter->startElement('a:p');
1755
1756            // a:pPr
1757            $objWriter->startElement('a:pPr');
1758
1759            // a:defRPr
1760            $objWriter->startElement('a:defRPr');
1761
1762            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1763            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1764            $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough());
1765            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1766            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1767            $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline());
1768
1769            // Font - a:solidFill
1770            $objWriter->startElement('a:solidFill');
1771
1772            $this->writeColor($objWriter, $series->getFont()->getColor());
1773
1774            $objWriter->endElement();
1775
1776            // Font - a:latin
1777            $objWriter->startElement('a:latin');
1778            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1779            $objWriter->endElement();
1780            // a:ea
1781            $objWriter->startElement('a:ea');
1782            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1783            $objWriter->endElement();
1784
1785            $objWriter->endElement();
1786
1787            $objWriter->endElement();
1788
1789            // a:endParaRPr
1790            $objWriter->startElement('a:endParaRPr');
1791            $objWriter->writeAttribute('lang', 'en-US');
1792            $objWriter->writeAttribute('dirty', '0');
1793            $objWriter->endElement();
1794
1795            $objWriter->endElement();
1796
1797            $objWriter->endElement();
1798
1799            // c:showVal
1800            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1801
1802            // c:showCatName
1803            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1804
1805            // c:showSerName
1806            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1807
1808            // c:showPercent
1809            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1810
1811            // c:showLeaderLines
1812            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1813
1814            // > c:dLbls
1815            $objWriter->endElement();
1816
1817            // Write X axis data
1818            $axisXData = array_keys($series->getValues());
1819
1820            // c:cat
1821            $objWriter->startElement('c:cat');
1822            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1823            $objWriter->endElement();
1824
1825            // Write Y axis data
1826            $axisYData = array_values($series->getValues());
1827
1828            // c:val
1829            $objWriter->startElement('c:val');
1830            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
1831            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1832            $objWriter->endElement();
1833
1834            // c:smooth
1835            $objWriter->startElement('c:smooth');
1836            $objWriter->writeAttribute('val', $subject->isSmooth() ? '1' : '0');
1837            $objWriter->endElement();
1838
1839            $objWriter->endElement();
1840
1841            ++$seriesIndex;
1842        }
1843
1844        // c:marker
1845        $objWriter->startElement('c:marker');
1846        $objWriter->writeAttribute('val', '1');
1847        $objWriter->endElement();
1848
1849        // c:axId
1850        $objWriter->startElement('c:axId');
1851        $objWriter->writeAttribute('val', '52743552');
1852        $objWriter->endElement();
1853
1854        // c:axId
1855        $objWriter->startElement('c:axId');
1856        $objWriter->writeAttribute('val', '52749440');
1857        $objWriter->endElement();
1858
1859        $objWriter->endElement();
1860    }
1861
1862    /**
1863     * Write Type Radar.
1864     *
1865     * @param XMLWriter $objWriter XML Writer
1866     */
1867    protected function writeTypeRadar(XMLWriter $objWriter, Radar $subject, bool $includeSheet = false): void
1868    {
1869        // c:scatterChart
1870        $objWriter->startElement('c:radarChart');
1871
1872        // c:radarStyle
1873        $objWriter->startElement('c:radarStyle');
1874        $objWriter->writeAttribute('val', 'marker');
1875        $objWriter->endElement();
1876
1877        // c:varyColors
1878        $objWriter->startElement('c:varyColors');
1879        $objWriter->writeAttribute('val', '0');
1880        $objWriter->endElement();
1881
1882        // Write series
1883        $seriesIndex = 0;
1884        foreach ($subject->getSeries() as $series) {
1885            // c:ser
1886            $objWriter->startElement('c:ser');
1887
1888            // c:idx
1889            $objWriter->startElement('c:idx');
1890            $objWriter->writeAttribute('val', $seriesIndex);
1891            $objWriter->endElement();
1892
1893            // c:order
1894            $objWriter->startElement('c:order');
1895            $objWriter->writeAttribute('val', $seriesIndex);
1896            $objWriter->endElement();
1897
1898            // c:tx
1899            $objWriter->startElement('c:tx');
1900            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1901            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1902            $objWriter->endElement();
1903
1904            // c:spPr
1905            $objWriter->startElement('c:spPr');
1906            // Write fill
1907            $this->writeFill($objWriter, $series->getFill());
1908            // Write outline
1909            $this->writeOutline($objWriter, $series->getOutline());
1910            // ## c:spPr
1911            $objWriter->endElement();
1912
1913            // Marker
1914            $this->writeSeriesMarker($objWriter, $series->getMarker());
1915
1916            // c:dLbls
1917            $objWriter->startElement('c:dLbls');
1918
1919            // c:txPr
1920            $objWriter->startElement('c:txPr');
1921
1922            // a:bodyPr
1923            $objWriter->writeElement('a:bodyPr', null);
1924
1925            // a:lstStyle
1926            $objWriter->writeElement('a:lstStyle', null);
1927
1928            // a:p
1929            $objWriter->startElement('a:p');
1930
1931            // a:pPr
1932            $objWriter->startElement('a:pPr');
1933
1934            // a:defRPr
1935            $objWriter->startElement('a:defRPr');
1936
1937            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1938            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1939            $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough());
1940            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1941            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1942            $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline());
1943
1944            // Font - a:solidFill
1945            $objWriter->startElement('a:solidFill');
1946
1947            $this->writeColor($objWriter, $series->getFont()->getColor());
1948
1949            $objWriter->endElement();
1950
1951            // Font - a:latin
1952            $objWriter->startElement('a:latin');
1953            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1954            $objWriter->endElement();
1955            // a:ea
1956            $objWriter->startElement('a:ea');
1957            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1958            $objWriter->endElement();
1959
1960            $objWriter->endElement();
1961
1962            $objWriter->endElement();
1963
1964            // a:endParaRPr
1965            $objWriter->startElement('a:endParaRPr');
1966            $objWriter->writeAttribute('lang', 'en-US');
1967            $objWriter->writeAttribute('dirty', '0');
1968            $objWriter->endElement();
1969
1970            $objWriter->endElement();
1971
1972            $objWriter->endElement();
1973
1974            // c:showLegendKey
1975            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1976
1977            // c:showVal
1978            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1979
1980            // c:showCatName
1981            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1982
1983            // c:showSerName
1984            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1985
1986            // c:showPercent
1987            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1988
1989            // c:showLeaderLines
1990            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1991
1992            $objWriter->endElement();
1993
1994            // Write X axis data
1995            $axisXData = array_keys($series->getValues());
1996
1997            // c:cat
1998            $objWriter->startElement('c:cat');
1999            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
2000            $objWriter->endElement();
2001
2002            // Write Y axis data
2003            $axisYData = array_values($series->getValues());
2004
2005            // c:val
2006            $objWriter->startElement('c:val');
2007            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
2008            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
2009            $objWriter->endElement();
2010
2011            $objWriter->endElement();
2012
2013            ++$seriesIndex;
2014        }
2015
2016        // c:axId
2017        $objWriter->startElement('c:axId');
2018        $objWriter->writeAttribute('val', '52743552');
2019        $objWriter->endElement();
2020
2021        // c:axId
2022        $objWriter->startElement('c:axId');
2023        $objWriter->writeAttribute('val', '52749440');
2024        $objWriter->endElement();
2025
2026        $objWriter->endElement();
2027    }
2028
2029    /**
2030     * Write Type Scatter.
2031     */
2032    protected function writeTypeScatter(XMLWriter $objWriter, Scatter $subject, bool $includeSheet = false): void
2033    {
2034        // c:scatterChart
2035        $objWriter->startElement('c:scatterChart');
2036
2037        // c:scatterStyle
2038        $objWriter->startElement('c:scatterStyle');
2039        $objWriter->writeAttribute('val', 'lineMarker');
2040        $objWriter->endElement();
2041
2042        // c:varyColors
2043        $objWriter->startElement('c:varyColors');
2044        $objWriter->writeAttribute('val', '0');
2045        $objWriter->endElement();
2046
2047        // Write series
2048        $seriesIndex = 0;
2049        foreach ($subject->getSeries() as $series) {
2050            // c:ser
2051            $objWriter->startElement('c:ser');
2052
2053            // c:idx
2054            $objWriter->startElement('c:idx');
2055            $objWriter->writeAttribute('val', $seriesIndex);
2056            $objWriter->endElement();
2057
2058            // c:order
2059            $objWriter->startElement('c:order');
2060            $objWriter->writeAttribute('val', $seriesIndex);
2061            $objWriter->endElement();
2062
2063            // c:tx
2064            $objWriter->startElement('c:tx');
2065            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
2066            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
2067            $objWriter->endElement();
2068
2069            // c:spPr
2070            $objWriter->startElement('c:spPr');
2071            // Write fill
2072            $this->writeFill($objWriter, $series->getFill());
2073            // Write outline
2074            $this->writeOutline($objWriter, $series->getOutline());
2075            // ## c:spPr
2076            $objWriter->endElement();
2077
2078            // Marker
2079            $this->writeSeriesMarker($objWriter, $series->getMarker());
2080
2081            // c:dLbls
2082            $objWriter->startElement('c:dLbls');
2083
2084            // c:txPr
2085            $objWriter->startElement('c:txPr');
2086
2087            // a:bodyPr
2088            $objWriter->writeElement('a:bodyPr', null);
2089
2090            // a:lstStyle
2091            $objWriter->writeElement('a:lstStyle', null);
2092
2093            // a:p
2094            $objWriter->startElement('a:p');
2095
2096            // a:pPr
2097            $objWriter->startElement('a:pPr');
2098
2099            // a:defRPr
2100            $objWriter->startElement('a:defRPr');
2101
2102            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
2103            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
2104            $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough());
2105            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
2106            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
2107            $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline());
2108
2109            // Font - a:solidFill
2110            $objWriter->startElement('a:solidFill');
2111
2112            $this->writeColor($objWriter, $series->getFont()->getColor());
2113
2114            $objWriter->endElement();
2115
2116            // Font - a:latin
2117            $objWriter->startElement('a:latin');
2118            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
2119            $objWriter->endElement();
2120            // a:ea
2121            $objWriter->startElement('a:ea');
2122            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
2123            $objWriter->endElement();
2124
2125            $objWriter->endElement();
2126
2127            $objWriter->endElement();
2128
2129            // a:endParaRPr
2130            $objWriter->startElement('a:endParaRPr');
2131            $objWriter->writeAttribute('lang', 'en-US');
2132            $objWriter->writeAttribute('dirty', '0');
2133            $objWriter->endElement();
2134
2135            $objWriter->endElement();
2136
2137            $objWriter->endElement();
2138
2139            // c:showLegendKey
2140            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
2141
2142            // c:showVal
2143            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
2144
2145            // c:showCatName
2146            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
2147
2148            // c:showSerName
2149            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
2150
2151            // c:showPercent
2152            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
2153
2154            // c:separator
2155            $separator = $series->getSeparator();
2156            if (!empty($separator) && PHP_EOL != $separator) {
2157                // c:dLbls\c:separator
2158                $objWriter->writeElement('c:separator', $separator);
2159            }
2160
2161            // c:showLeaderLines
2162            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
2163
2164            $objWriter->endElement();
2165
2166            // Write X axis data
2167            $axisXData = array_keys($series->getValues());
2168
2169            // c:xVal
2170            $objWriter->startElement('c:xVal');
2171            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
2172            $objWriter->endElement();
2173
2174            // Write Y axis data
2175            $axisYData = array_values($series->getValues());
2176
2177            // c:yVal
2178            $objWriter->startElement('c:yVal');
2179            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
2180            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
2181            $objWriter->endElement();
2182
2183            // c:smooth
2184            $objWriter->startElement('c:smooth');
2185            $objWriter->writeAttribute('val', $subject->isSmooth() ? '1' : '0');
2186            $objWriter->endElement();
2187
2188            $objWriter->endElement();
2189
2190            ++$seriesIndex;
2191        }
2192
2193        // c:axId
2194        $objWriter->startElement('c:axId');
2195        $objWriter->writeAttribute('val', '52743552');
2196        $objWriter->endElement();
2197
2198        // c:axId
2199        $objWriter->startElement('c:axId');
2200        $objWriter->writeAttribute('val', '52749440');
2201        $objWriter->endElement();
2202
2203        $objWriter->endElement();
2204    }
2205
2206    /**
2207     * Write chart relationships to XML format.
2208     *
2209     * @return string XML Output
2210     */
2211    protected function writeChartRelationships(Chart $pChart): string
2212    {
2213        // Create XML writer
2214        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
2215
2216        // XML header
2217        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
2218
2219        // Relationships
2220        $objWriter->startElement('Relationships');
2221        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
2222
2223        // Write spreadsheet relationship?
2224        if ($pChart->hasIncludedSpreadsheet()) {
2225            $this->writeRelationship($objWriter, 1, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/package', '../embeddings/' . $pChart->getIndexedFilename() . '.xlsx');
2226        }
2227
2228        $objWriter->endElement();
2229
2230        // Return
2231        return $objWriter->getData();
2232    }
2233
2234    protected function writeSeriesMarker(XMLWriter $objWriter, Chart\Marker $marker): void
2235    {
2236        // c:marker
2237        $objWriter->startElement('c:marker');
2238        // c:marker > c:symbol
2239        $objWriter->startElement('c:symbol');
2240        $objWriter->writeAttribute('val', $marker->getSymbol());
2241        $objWriter->endElement();
2242
2243        // Size if different of none
2244        if (Chart\Marker::SYMBOL_NONE != $marker->getSymbol()) {
2245            $markerSize = (int) $marker->getSize();
2246            if ($markerSize < 2) {
2247                $markerSize = 2;
2248            }
2249            if ($markerSize > 72) {
2250                $markerSize = 72;
2251            }
2252
2253            /*
2254             * c:marker > c:size
2255             * Size in points
2256             * @link : https://msdn.microsoft.com/en-us/library/hh658135(v=office.12).aspx
2257             */
2258            $objWriter->startElement('c:size');
2259            $objWriter->writeAttribute('val', $markerSize);
2260            $objWriter->endElement();
2261        }
2262
2263        // // c:marker > c:spPr
2264        $objWriter->startElement('c:spPr');
2265        $this->writeFill($objWriter, $marker->getFill());
2266        $this->writeBorder($objWriter, $marker->getBorder(), '', true);
2267        $objWriter->endElement();
2268
2269        // > c:marker
2270        $objWriter->endElement();
2271    }
2272
2273    protected function writeAxis(XMLWriter $objWriter, Chart\Axis $oAxis, string $typeAxis, Chart\Type\AbstractType $typeChart): void
2274    {
2275        if (Chart\Axis::AXIS_X != $typeAxis && Chart\Axis::AXIS_Y != $typeAxis) {
2276            return;
2277        }
2278
2279        $crossesAt = $oAxis->getCrossesAt();
2280        $orientation = $oAxis->isReversedOrder() ? 'maxMin' : 'minMax';
2281
2282        if (Chart\Axis::AXIS_X == $typeAxis) {
2283            $mainElement = 'c:catAx';
2284            $axIdVal = '52743552';
2285            $axPosVal = $crossesAt === 'max' ? 't' : 'b';
2286            $crossAxVal = '52749440';
2287        } else {
2288            $mainElement = 'c:valAx';
2289            $axIdVal = '52749440';
2290            $axPosVal = $crossesAt === 'max' ? 'r' : 'l';
2291            $crossAxVal = '52743552';
2292        }
2293
2294        // $mainElement
2295        $objWriter->startElement($mainElement);
2296
2297        // $mainElement > c:axId
2298        $objWriter->startElement('c:axId');
2299        $objWriter->writeAttribute('val', $axIdVal);
2300        $objWriter->endElement();
2301
2302        // $mainElement > c:scaling
2303        $objWriter->startElement('c:scaling');
2304
2305        // $mainElement > c:scaling > c:orientation
2306        $objWriter->startElement('c:orientation');
2307        $objWriter->writeAttribute('val', $orientation);
2308        $objWriter->endElement();
2309
2310        if (null !== $oAxis->getMaxBounds()) {
2311            $objWriter->startElement('c:max');
2312            $objWriter->writeAttribute('val', $oAxis->getMaxBounds());
2313            $objWriter->endElement();
2314        }
2315
2316        if (null !== $oAxis->getMinBounds()) {
2317            $objWriter->startElement('c:min');
2318            $objWriter->writeAttribute('val', $oAxis->getMinBounds());
2319            $objWriter->endElement();
2320        }
2321
2322        // $mainElement > ##c:scaling
2323        $objWriter->endElement();
2324
2325        // $mainElement > c:delete
2326        $objWriter->startElement('c:delete');
2327        $objWriter->writeAttribute('val', $oAxis->isVisible() ? '0' : '1');
2328        $objWriter->endElement();
2329
2330        // $mainElement > c:axPos
2331        $objWriter->startElement('c:axPos');
2332        $objWriter->writeAttribute('val', $axPosVal);
2333        $objWriter->endElement();
2334
2335        $oMajorGridlines = $oAxis->getMajorGridlines();
2336        if ($oMajorGridlines instanceof Gridlines) {
2337            $objWriter->startElement('c:majorGridlines');
2338
2339            $this->writeAxisGridlines($objWriter, $oMajorGridlines);
2340
2341            $objWriter->endElement();
2342        }
2343
2344        $oMinorGridlines = $oAxis->getMinorGridlines();
2345        if ($oMinorGridlines instanceof Gridlines) {
2346            $objWriter->startElement('c:minorGridlines');
2347
2348            $this->writeAxisGridlines($objWriter, $oMinorGridlines);
2349
2350            $objWriter->endElement();
2351        }
2352
2353        if ('' != $oAxis->getTitle()) {
2354            // c:title
2355            $objWriter->startElement('c:title');
2356
2357            // c:tx
2358            $objWriter->startElement('c:tx');
2359
2360            // c:rich
2361            $objWriter->startElement('c:rich');
2362
2363            // a:bodyPr
2364            $objWriter->startElement('a:bodyPr');
2365            $objWriter->writeAttributeIf($oAxis->getTitleRotation() != 0, 'rot', CommonDrawing::degreesToAngle((int) $oAxis->getTitleRotation()));
2366            $objWriter->endElement();
2367
2368            // a:lstStyle
2369            $objWriter->writeElement('a:lstStyle', null);
2370
2371            // a:p
2372            $objWriter->startElement('a:p');
2373
2374            // a:pPr
2375            $objWriter->startElement('a:pPr');
2376
2377            // a:defRPr
2378            $objWriter->startElement('a:defRPr');
2379
2380            $objWriter->writeAttribute('b', ($oAxis->getFont()->isBold() ? 'true' : 'false'));
2381            $objWriter->writeAttribute('i', ($oAxis->getFont()->isItalic() ? 'true' : 'false'));
2382            $objWriter->writeAttribute('strike', $oAxis->getFont()->getStrikethrough());
2383            $objWriter->writeAttribute('sz', ($oAxis->getFont()->getSize() * 100));
2384            $objWriter->writeAttribute('u', $oAxis->getFont()->getUnderline());
2385            $objWriter->writeAttributeIf($oAxis->getFont()->getBaseline() !== 0, 'baseline', $oAxis->getFont()->getBaseline());
2386
2387            // Font - a:solidFill
2388            $objWriter->startElement('a:solidFill');
2389            $this->writeColor($objWriter, $oAxis->getFont()->getColor());
2390            $objWriter->endElement();
2391
2392            // Font - a:latin
2393            $objWriter->startElement('a:latin');
2394            $objWriter->writeAttribute('typeface', $oAxis->getFont()->getName());
2395            $objWriter->endElement();
2396            // a:ea
2397            $objWriter->startElement('a:ea');
2398            $objWriter->writeAttribute('typeface', $oAxis->getFont()->getName());
2399            $objWriter->endElement();
2400
2401            $objWriter->endElement();
2402
2403            // ## a:pPr
2404            $objWriter->endElement();
2405
2406            // a:r
2407            $objWriter->startElement('a:r');
2408
2409            // a:rPr
2410            $objWriter->startElement('a:rPr');
2411            $objWriter->writeAttribute('lang', 'en-US');
2412            $objWriter->writeAttribute('dirty', '0');
2413            $objWriter->endElement();
2414
2415            // a:t
2416            $objWriter->writeElement('a:t', $oAxis->getTitle());
2417
2418            // ## a:r
2419            $objWriter->endElement();
2420
2421            // a:endParaRPr
2422            $objWriter->startElement('a:endParaRPr');
2423            $objWriter->writeAttribute('lang', 'en-US');
2424            $objWriter->writeAttribute('dirty', '0');
2425            $objWriter->endElement();
2426
2427            // ## a:p
2428            $objWriter->endElement();
2429
2430            // ## c:rich
2431            $objWriter->endElement();
2432
2433            // ## c:tx
2434            $objWriter->endElement();
2435
2436            // ## c:title
2437            $objWriter->endElement();
2438        }
2439
2440        // c:numFmt
2441        $objWriter->startElement('c:numFmt');
2442        $objWriter->writeAttribute('formatCode', $oAxis->getFormatCode());
2443        $objWriter->writeAttribute('sourceLinked', '1');
2444        $objWriter->endElement();
2445
2446        // c:majorTickMark
2447        $objWriter->startElement('c:majorTickMark');
2448        $objWriter->writeAttribute('val', $oAxis->getMajorTickMark());
2449        $objWriter->endElement();
2450
2451        // c:minorTickMark
2452        $objWriter->startElement('c:minorTickMark');
2453        $objWriter->writeAttribute('val', $oAxis->getMinorTickMark());
2454        $objWriter->endElement();
2455
2456        // c:tickLblPos
2457        $objWriter->startElement('c:tickLblPos');
2458        $objWriter->writeAttribute('val', $oAxis->getTickLabelPosition());
2459        $objWriter->endElement();
2460
2461        // c:spPr
2462        $objWriter->startElement('c:spPr');
2463        $this->writeOutline($objWriter, $oAxis->getOutline());
2464        $objWriter->endElement();
2465
2466        // c:txPr
2467        $objWriter->startElement('c:txPr');
2468
2469        // a:bodyPr
2470        $objWriter->writeElement('a:bodyPr', null);
2471
2472        // a:lstStyle
2473        $objWriter->writeElement('a:lstStyle', null);
2474
2475        // a:p
2476        $objWriter->startElement('a:p');
2477
2478        // a:pPr
2479        $objWriter->startElement('a:pPr');
2480
2481        // a:defRPr
2482        $objWriter->startElement('a:defRPr');
2483        $objWriter->writeAttribute('b', ($oAxis->getTickLabelFont()->isBold() ? 'true' : 'false'));
2484        $objWriter->writeAttribute('i', ($oAxis->getTickLabelFont()->isItalic() ? 'true' : 'false'));
2485        $objWriter->writeAttribute('strike', $oAxis->getFont()->getStrikethrough());
2486        $objWriter->writeAttribute('sz', ($oAxis->getTickLabelFont()->getSize() * 100));
2487        $objWriter->writeAttribute('u', $oAxis->getTickLabelFont()->getUnderline());
2488        $objWriter->writeAttributeIf($oAxis->getTickLabelFont()->getBaseline() !== 0, 'baseline', $oAxis->getTickLabelFont()->getBaseline());
2489
2490        // Font - a:solidFill
2491        $objWriter->startElement('a:solidFill');
2492        $this->writeColor($objWriter, $oAxis->getTickLabelFont()->getColor());
2493        $objWriter->endElement();
2494
2495        // Font - a:latin
2496        $objWriter->startElement('a:latin');
2497        $objWriter->writeAttribute('typeface', $oAxis->getTickLabelFont()->getName());
2498        $objWriter->endElement();
2499
2500        // Font - a:ea
2501        $objWriter->startElement('a:ea');
2502        $objWriter->writeAttribute('typeface', $oAxis->getTickLabelFont()->getName());
2503        $objWriter->endElement();
2504
2505        //## a:defRPr
2506        $objWriter->endElement();
2507
2508        //## a:pPr
2509        $objWriter->endElement();
2510
2511        // a:endParaRPr
2512        $objWriter->startElement('a:endParaRPr');
2513        $objWriter->writeAttribute('lang', 'en-US');
2514        $objWriter->writeAttribute('dirty', '0');
2515        $objWriter->endElement();
2516
2517        // ## a:p
2518        $objWriter->endElement();
2519
2520        // ## c:txPr
2521        $objWriter->endElement();
2522
2523        // c:crossAx
2524        $objWriter->startElement('c:crossAx');
2525        $objWriter->writeAttribute('val', $crossAxVal);
2526        $objWriter->endElement();
2527
2528        // c:crosses "autoZero" | "min" | "max" | custom string value
2529        if (in_array($crossesAt, ['autoZero', 'min', 'max'])) {
2530            $objWriter->startElement('c:crosses');
2531            $objWriter->writeAttribute('val', $crossesAt);
2532            $objWriter->endElement();
2533        } else {
2534            $objWriter->startElement('c:crossesAt');
2535            $objWriter->writeAttribute('val', $crossesAt);
2536            $objWriter->endElement();
2537        }
2538
2539        if (Chart\Axis::AXIS_X == $typeAxis) {
2540            // c:lblAlgn
2541            $objWriter->startElement('c:lblAlgn');
2542            $objWriter->writeAttribute('val', 'ctr');
2543            $objWriter->endElement();
2544
2545            // c:lblOffset
2546            $objWriter->startElement('c:lblOffset');
2547            $objWriter->writeAttribute('val', '100');
2548            $objWriter->endElement();
2549
2550            // c:majorUnit
2551            if ($oAxis->getMajorUnit() !== null) {
2552                $objWriter->startElement('c:tickLblSkip');
2553                $objWriter->writeAttribute('val', $oAxis->getMajorUnit());
2554                $objWriter->endElement();
2555            }
2556        }
2557
2558        if (Chart\Axis::AXIS_Y == $typeAxis) {
2559            // c:crossBetween
2560            $objWriter->startElement('c:crossBetween');
2561            // midCat : Position Axis On Tick Marks
2562            // between : Between Tick Marks
2563            if ($typeChart instanceof Area) {
2564                $objWriter->writeAttribute('val', 'midCat');
2565            } else {
2566                $objWriter->writeAttribute('val', 'between');
2567            }
2568            $objWriter->endElement();
2569
2570            // c:majorUnit
2571            if ($oAxis->getMajorUnit() !== null) {
2572                $objWriter->startElement('c:majorUnit');
2573                $objWriter->writeAttribute('val', $oAxis->getMajorUnit());
2574                $objWriter->endElement();
2575            }
2576
2577            // c:minorUnit
2578            if ($oAxis->getMinorUnit() !== null) {
2579                $objWriter->startElement('c:minorUnit');
2580                $objWriter->writeAttribute('val', $oAxis->getMinorUnit());
2581                $objWriter->endElement();
2582            }
2583        }
2584
2585        $objWriter->endElement();
2586    }
2587
2588    protected function writeAxisGridlines(XMLWriter $objWriter, Gridlines $oGridlines): void
2589    {
2590        // c:spPr
2591        $objWriter->startElement('c:spPr');
2592
2593        // Outline
2594        $this->writeOutline($objWriter, $oGridlines->getOutline());
2595
2596        // ##c:spPr
2597        $objWriter->endElement();
2598    }
2599}